
/*
 *    GeoTools - The Open Source Java GIS Tookit
 *    http://geotools.org
 *
 *    (C) 2006-2008, Open Source Geospatial Foundation (OSGeo)
 *
 *    This file is hereby placed into the Public Domain. This means anyone is
 *    free to do whatever they wish with this file. Use it well and enjoy!
 */
// private static final Color LINE_COLOUR = Color.RED;
//    private static final Color FILL_COLOUR = Color.CYAN;
//    private static final Color SELECTED_COLOUR = Color.YELLOW;
//    private static final float OPACITY = 4.0f;
//    private static final float LINE_WIDTH = 4.0f;
//    private static final float POINT_SIZE = 10.0f;
// docs start source
/*
 *    GeoTools - The Open Source Java GIS Tookit
 *    http://geotools.org
 *
 *    (C) 2006-2008, Open Source Geospatial Foundation (OSGeo)
 *
 *    This file is hereby placed into the Public Domain. This means anyone is
 *    free to do whatever they wish with this file. Use it well and enjoy!
 */
package org.geotools.demo;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequences;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineSegment;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JToolBar;
import org.geotools.data.FeatureSource;
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureCollections;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.filter.text.cql2.CQL;
import org.geotools.filter.text.cql2.CQLException;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.map.DefaultMapContext;
import org.geotools.map.MapContext;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.Fill;
import org.geotools.styling.Graphic;
import org.geotools.styling.Mark;
import org.geotools.styling.Rule;
import org.geotools.styling.Stroke;
import org.geotools.styling.Style;
import org.geotools.styling.StyleFactory;
import org.geotools.styling.Symbolizer;
import org.geotools.swing.JMapFrame;
import org.geotools.swing.event.MapMouseEvent;
import org.geotools.swing.tool.CursorTool;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.identity.FeatureId;


/**
 * In this example we create a map tool to select a feature clicked
 * with the mouse. The selected feature will be painted yellow.
 *
 * @source $URL: http://svn.osgeo.org/geotools/tags/2.6.1/demo/example/src/main/java/org/geotools/demo/SelectionLab.java $
 */
public class SelectionLab {

    /*
     * Factories that we will use to create style and filter objects
     */
    private StyleFactory sf = CommonFactoryFinder.getStyleFactory(null);
    private FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);

    /*
     * Convenient constants for the type of feature geometry in the shapefile
     */
    private enum GeomType {

        POINT, LINE, POLYGON
    };

    /*
     * Some default style variables
     */
    private static final Color LINE_COLOUR = Color.RED;
    private static final Color FILL_COLOUR = Color.RED;
    private static final Color SELECTED_COLOUR = Color.YELLOW;
    private static final float OPACITY = 1.0f;
    private static final float LINE_WIDTH = 4.0f;
    private static final float POINT_SIZE = 10.0f;
    private static final int RAY = 10;
    private JMapFrame mapFrame;
    private FeatureSource<SimpleFeatureType, SimpleFeature> featureSource;
    private String geometryAttributeName;
    private GeomType geometryType;
    FeatureCollection<SimpleFeatureType, SimpleFeature> collection;
    FeatureCollection<SimpleFeatureType, SimpleFeature> collectionPoint;
    /*
     * The application method
     */

    public static void main(String[] args) throws Exception {
        SelectionLab me = new SelectionLab();

//        File file = JFileDataStoreChooser.showOpenFile("shp", null);
//        if (file == null) {
//            return;
//        }

        me.displayShapefile(new File("ul1\\ul1.shp"));
    }
// docs end main

// docs start display shapefile
    /**
     * This method connects to the shapefile; retrieves information about
     * its features; creates a map frame to display the shapefile and adds
     * a custom feature selection tool to the toolbar of the map frame.
     */
    public void displayShapefile(File file) throws Exception {
        FileDataStore store = FileDataStoreFinder.getDataStore(file);

        SimpleFeatureType simpleFT;// = DataUtilities.createType("the_geom", "location:LineString:srid=4326, name:String");
        //line segment



        //linia
        SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
        builder.setName("the_geom");
        builder.setCRS(DefaultGeographicCRS.WGS84);
        builder.add("Location", MultiLineString.class);
        builder.length(15).add("Name", String.class);
        simpleFT = builder.buildFeatureType();
        //end linia
        //ogolne
        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
        WKTReader reader = new WKTReader(geometryFactory);
        //end ogolne
         featureSource = store.getFeatureSource();
        FeatureCollection<SimpleFeatureType,SimpleFeature> fc = featureSource.getFeatures();

        SimpleFeatureBuilder simpleFeatureBuilder = new SimpleFeatureBuilder(simpleFT);
        Iterator<SimpleFeature> it = fc.iterator();
        SimpleFeature feature;
        collection = FeatureCollections.newCollection();
        while (it.hasNext()){
            MultiLineString ml = (MultiLineString) it.next().getDefaultGeometry();
           simpleFeatureBuilder.add(ml);
           simpleFeatureBuilder.add("the_geom");
           feature = simpleFeatureBuilder.buildFeature(null);
           collection.add(feature);
        }
        Coordinate[] tabC = {new Coordinate(-1612,88),new Coordinate(1027,88)};
       LineString ls =  geometryFactory.createLineString(tabC);
       LineString[] lsTab = {ls};
       System.out.println(ls +"-----------------------");
       MultiLineString lm = geometryFactory.createMultiLineString(lsTab);
       simpleFeatureBuilder.add(lm);
       simpleFeatureBuilder.add("the_geom");
       feature = simpleFeatureBuilder.buildFeature(null);
       collection.add(feature);
//        LineString line = (LineString) reader.read("LINESTRING(-1612.8 88.005693950172781,10.37081850534 88.0056939501781,1027.37081850534 88.0056939501781)");

        
//        simpleFeatureBuilder.add(line);
//        simpleFeatureBuilder.add("the_geom");
        
        
        

//---------------------------------------PUNKT---------------------------------
        SimpleFeatureTypeBuilder builderPoint = new SimpleFeatureTypeBuilder();
        builderPoint.setName("the_geomP");
        builderPoint.setCRS(DefaultGeographicCRS.WGS84);
        builderPoint.add("Location", Polygon.class);
        builderPoint.length(15).add("Name", String.class);
        SimpleFeatureType simpleFTPoint;
        simpleFTPoint = builderPoint.buildFeatureType();
        SimpleFeatureBuilder simpleFeatureBuilderPoint = new SimpleFeatureBuilder(simpleFTPoint);


        Polygon point = (Polygon) reader.read(("POLYGON((-100 -100, -100 100, 100 100, 100 -100, -100 -100))"));
        simpleFeatureBuilderPoint.add(point);
        simpleFeatureBuilderPoint.add("point");
        SimpleFeature featurePoint = simpleFeatureBuilder.buildFeature(null);
        featurePoint = simpleFeatureBuilderPoint.buildFeature(null);
        collectionPoint = FeatureCollections.newCollection();
        collectionPoint.add(featurePoint);

       
       
       
//        FeatureSource<SimpleFeatureType, SimpleFeature> featureSource2;
//        featureSource2 = store2.getFeatureSource();
        System.out.println(collection.size()+"++++++++++++++++++++++++++++++++");
        setGeometry();
//setGeometry();
        /*
         * Create the JMapFrame and set it to display the shapefile's features
         * with a default line and colour style
         */
        MapContext map = new DefaultMapContext();
        map.setTitle("Mapa miasta");
        Style style = createDefaultStyle();
        Style style2 = createDefaultStyle2();
//        map.addLayer(featureSource, style);
        map.addLayer(collection, style2);
        map.addLayer(collectionPoint, style);


        mapFrame = new JMapFrame(map);
        mapFrame.enableToolBar(true);
        mapFrame.enableStatusBar(true);

        /*
         * Before making the map frame visible we add a new button to its
         * toolbar for our custom feature selection tool
         */
        JToolBar toolBar = mapFrame.getToolBar();
        JButton btn = new JButton("Select");
        toolBar.addSeparator();
        toolBar.add(btn);

        /*
         * When the user clicks the button we want to enable
         * our custom feature selection tool. Since the only
         * mouse action we are intersted in is 'clicked', and
         * we are not creating control icons or cursors here,
         * we can just create our tool as an anonymous sub-class
         * of CursorTool.
         */
        btn.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                mapFrame.getMapPane().setCursorTool(
                        new CursorTool() {

                            @Override
                            public void onMouseClicked(MapMouseEvent ev) {
                                try {
                                    try {
                                        selectFeatures(ev);
                                    } catch (ParseException ex) {
                                        Logger.getLogger(SelectionLab.class.getName()).log(Level.SEVERE, null, ex);
                                    }
                                } catch (CQLException ex) {
                                    Logger.getLogger(SelectionLab.class.getName()).log(Level.SEVERE, null, ex);
                                }
                            }
                        });
            }
        });

        /**
         * Finally, we display the map frame. When it is closed
         * this application will exit.
         */
        mapFrame.setSize(600, 600);
        mapFrame.setVisible(true);
    }
// docs end display shapefile

// docs start select features
    /**
     * This method is called by our feature selection tool when
     * the user has clicked on the map.
     *
     * @param pos map (world) coordinates of the mouse cursor
     */
    void selectFeatures(MapMouseEvent ev) throws CQLException, ParseException {

        System.out.println("Mouse click at: " + ev.getMapPosition());
        System.out.println(geometryAttributeName + "geometry");
        /*
         * Construct a 5x5 pixel rectangle centred on the mouse click position
         */
        java.awt.Point screenPos = ev.getPoint();
        Rectangle screenRect = new Rectangle(screenPos.x - 2, screenPos.y - 2, 5, 5);

        /*
         * Transform the screen rectangle into bounding box in the coordinate
         * reference system of our map context. Note: we are using a naive method
         * here but GeoTools also offers other, more accurate methods.
         */
        AffineTransform screenToWorld = mapFrame.getMapPane().getScreenToWorldTransform();
        Rectangle2D worldRect = screenToWorld.createTransformedShape(screenRect).getBounds2D();
        ReferencedEnvelope bbox = new ReferencedEnvelope(
                worldRect,
                mapFrame.getMapContext().getCoordinateReferenceSystem());

        /*
         * Create a Filter to select features that intersect with
         * the bounding box
         */
//        Filter filter = ff.bbox(ff.property(geometryAttributeName), bbox);
        Double x = ev.getMapPosition().x;
        Double y = ev.getMapPosition().y;
        String xS = x.toString();
        String yS = y.toString();
        String pointS = "POINT(" + xS + " " + yS + ")"; //"LINESTRING(-1612.8 88.005693950172781,10.37081850534 88.0056939501781,1027.37081850534 88.0056939501781)";

        ArrayList<LineString> arrayLine = getNeighbourPoints(ev, RAY);
        Filter filter = CQL.toFilter("CROSSES(" + geometryAttributeName + "," + arrayLine.get(0) + ")");
//        Filter filter = CQL.toFilter("INTERSECT(the_geom,LINESTRING(-1612.8 88.005693950172781,10.37081850534 88.0056939501781,1027.37081850534 88.0056939501781))");

        /*
         * Use the filter to identify the selected features
         */
        try {
            FeatureCollection<SimpleFeatureType, SimpleFeature> selectedFeatures =
                    featureSource.getFeatures(filter);
            System.out.println(selectedFeatures.size());
            FeatureIterator<SimpleFeature> iter = selectedFeatures.features();
            Set<FeatureId> IDs = new HashSet<FeatureId>();
            try {
                while (iter.hasNext()) {
                    SimpleFeature feature = iter.next();
                    IDs.add(feature.getIdentifier());

                    System.out.println("   " + feature.getAttributes());
                }

            } finally {
                iter.close();
            }

            if (IDs.isEmpty()) {
                System.out.println("   no feature selected");
            }

            displaySelectedFeatures(IDs);

        } catch (Exception ex) {
            ex.printStackTrace();
            return;
        }
    }
// docs end select features

// docs start display selected
    /**
     * Sets the display to paint selected features yellow and
     * unselected features in the default style.
     *
     * @param IDs identifiers of currently selected features
     */
    public void displaySelectedFeatures(Set<FeatureId> IDs) {
        Style style;

        if (IDs.isEmpty()) {
            style = createDefaultStyle();

        } else {
            style = createSelectedStyle(IDs);
        }

        mapFrame.getMapContext().getLayer(0).setStyle(style);
        mapFrame.getMapPane().repaint();
    }
// docs end display selected

// docs start default style
    /**
     * Create a default Style for feature display
     */
    private Style createDefaultStyle() {
        Rule rule = createRule(Color.BLUE, Color.BLUE);

        FeatureTypeStyle fts = sf.createFeatureTypeStyle();
        fts.rules().add(rule);

        Style style = sf.createStyle();
        style.featureTypeStyles().add(fts);
        return style;
    }

    private Style createDefaultStyle2() {
        Rule rule = createRule(Color.PINK, FILL_COLOUR);

        FeatureTypeStyle fts = sf.createFeatureTypeStyle();
        fts.rules().add(rule);

        Style style = sf.createStyle();
        style.featureTypeStyles().add(fts);
        return style;
    }
// docs end default style

// docs start selected style
    /**
     * Create a Style where features with given IDs are painted
     * yellow, while others are painted with the default colors.
     */
    private Style createSelectedStyle(Set<FeatureId> IDs) {
        Rule selectedRule = createRule(SELECTED_COLOUR, SELECTED_COLOUR);
        selectedRule.setFilter(ff.id(IDs));

        Rule otherRule = createRule(LINE_COLOUR, FILL_COLOUR);
        otherRule.setElseFilter(true);

        FeatureTypeStyle fts = sf.createFeatureTypeStyle();
        fts.rules().add(selectedRule);
        fts.rules().add(otherRule);

        Style style = sf.createStyle();
        style.featureTypeStyles().add(fts);
        return style;
    }
// docs end selected style

// docs start create rule
    /**
     * Helper for createXXXStyle methods. Creates a new Rule containing
     * a Symbolizer tailored to the geometry type of the features that
     * we are displaying.
     */
    private Rule createRule(Color outlineColor, Color fillColor) {
        Symbolizer symbolizer = null;
        Fill fill = null;
        Stroke stroke = sf.createStroke(ff.literal(outlineColor), ff.literal(LINE_WIDTH));

        switch (geometryType) {
            case POLYGON:
                fill = sf.createFill(ff.literal(fillColor), ff.literal(OPACITY));
                symbolizer = sf.createPolygonSymbolizer(stroke, fill, geometryAttributeName);
                break;

            case LINE:
                symbolizer = sf.createLineSymbolizer(stroke, geometryAttributeName);
                break;

            case POINT:
                fill = sf.createFill(ff.literal(fillColor), ff.literal(OPACITY));

                Mark mark = sf.getCircleMark();
                mark.setFill(fill);
                mark.setStroke(stroke);

                Graphic graphic = sf.createDefaultGraphic();
                graphic.graphicalSymbols().clear();
                graphic.graphicalSymbols().add(mark);
                graphic.setSize(ff.literal(POINT_SIZE));

                symbolizer = sf.createPointSymbolizer(graphic, geometryAttributeName);
        }

        Rule rule = sf.createRule();
        rule.symbolizers().add(symbolizer);
        return rule;
    }
// docs end create rule

// docs start set geometry
    /**
     * Retrieve information about the feature geometry
     */
    private void setGeometry() {
        GeometryDescriptor geomDesc = collectionPoint.getSchema().getGeometryDescriptor();

        geometryAttributeName = geomDesc.getLocalName();

        Class<?> clazz = geomDesc.getType().getBinding();

        if (Polygon.class.isAssignableFrom(clazz)
                || MultiPolygon.class.isAssignableFrom(clazz)) {
            geometryType = GeomType.POLYGON;

        } else if (LineString.class.isAssignableFrom(clazz)
                || MultiLineString.class.isAssignableFrom(clazz)) {

            geometryType = GeomType.LINE;

        } else {
            geometryType = GeomType.POINT;
        }

    }
// docs end set geometry

    private void setGeometry2() {
//        GeometryDescriptor geomDesc = featureSource.getSchema().getGeometryDescriptor();
        GeometryDescriptor geomDesc = collectionPoint.getSchema().getGeometryDescriptor();
        geometryAttributeName = geomDesc.getLocalName();
        System.out.println(geomDesc + " deskryptor");
        Class<?> clazz = geomDesc.getType().getBinding();

        if (Polygon.class.isAssignableFrom(clazz)
                || MultiPolygon.class.isAssignableFrom(clazz)) {
            geometryType = GeomType.POLYGON;

        } else if (LineString.class.isAssignableFrom(clazz)
                || MultiLineString.class.isAssignableFrom(clazz)) {

            geometryType = GeomType.LINE;

        } else {
            geometryType = GeomType.POINT;
        }

    }

    private ArrayList<LineString> getNeighbourPoints(MapMouseEvent ev, int ray) throws ParseException {
        Double x = ev.getMapPosition().x;
        Double y = ev.getMapPosition().y;
        Double x2 = x + ray;
        Double y2 = y + ray;
        x -= ray;
        y -= ray;
        String xS = x.toString();
        String yS = y.toString();
        String xE = x2.toString();
        String yE = y2.toString();

        GeometryFactory geometryFactory = new GeometryFactory();
        WKTReader reader = new WKTReader(geometryFactory);
        LineString line = (LineString) reader.read("LINESTRING(" + xS + " " + yS + "," + xE + " " + yE + ")");
        line.setSRID(4326);
        System.out.println(line);
        ArrayList<LineString> arrayLine = new ArrayList<LineString>();

        arrayLine.add(line);

        return arrayLine;



    }
}
